#include "stdafx.h";
#include "Game.h";
#include <iostream>
#include <fstream>
#include <list>

using namespace std;


Game::Game()
{
	myCol = Color::WHITE;
	InitFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
	last = NULL;
	lastmove = new char[4];
	myTurn = true;
}

Game::Game(Color c)
{
	myCol = c;
	InitFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
	//InitFEN = "rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2";
	isChecked = false;
	last = NULL;
	lastmove = new char[4];

	/*if (c == Color::WHITE) myTurn = true;
	else myTurn = false;*/
}

void Game::Init()
{
	int x = 0;
	int index = 0;
	
	// Read board.
	for(int i=0;i<10;i++)
	{
		for (int j =0;j < 10; j++)
		{
			if (i==0 || j==0 || i==9 || j==9)
			{
				board[i][j] = NULL;
			}
			else
			{
				//Set board from FEN notation
				if (x == 0)
				{
					char c = InitFEN[index];
					index++;
					int tmp = (int)c-(int)'0';
					if (tmp > 0 && tmp < 9)
					{
						x = tmp - 1;
						board[i][j] = NULL;
					}
					else
					{
						SetPiece(i, j, c);
					}
				}
				else
				{
					board[i][j] = NULL;
					x--;
				}
			}
		}
		if (InitFEN[index]=='/') index++;
	}

	index++;

	if ((InitFEN[index] == 'w' && myCol == Color::WHITE) || (InitFEN[index] == 'b' && myCol == Color::BLACK))
	{
		myTurn = true;
	}
	else
	{
		myTurn == false;
	}

	index++;
	
	// Read castling
	while (InitFEN[index] != ' ')
	{
		castling += InitFEN[index];
		index++;
	}

	index++;

	// Read enpasant
	if (InitFEN[index] == '-')
	{
		enpasant.x = 0;
		enpasant.y = 0;
	}
	else
	{
		enpasant.x = InitFEN[index];
		index++;
		enpasant.y = InitFEN[index];
		index++;
	}

	index++;

	//Read halfmove and fullmove time

}


void Game::LoadGame()
{
}

int Game::Move(char *mv)
{
	//if (!myTurn) return -1;
	int fromx = mv[0] - 'a' + 1;
	int fromy = mv[1] - '0';
	int tox = mv[2] - 'a' + 1;
	int toy = mv[3] - '0';
	Piece * p1 = board[fromx][fromy];
	Piece * p2 = board[tox][toy];
	last = p2; //Remember last piece

	bool king = true; //if moved piece is king.

	if (!isValidMove(tox, toy, fromx, fromy, p1->tp)) //If not valid move, return -1
	{
		return -1;
	}

	if (p2 != NULL)
	{
		if(p1->col != p2->col)
		{
			if (p2->col == Color::BLACK) 
				capturedB.push_back(*board[tox][toy]);
			else capturedW.push_back(*board[tox][toy]);
			//return 0;
		}
		else
		{
			return -1;
		}
	}

	//last = board[tox][toy];
	board[tox][toy] = board[fromx][fromy];
	board[fromx][fromy] = NULL;

	int x, y;

	Color c = p1->col;

	for (int i=1; i<9; i++)
	{
		for (int j=1; j<9; j++)
		{
			if (board[i][j] != NULL && board[i][j]->col == c && board[i][j]->tp == PieceType::TP_KING)
			{
				x = i;
				y = j;
				break;
				break;
			}
		}
	}

	
	if (isAttacked(x,y, myCol)) //if king was moved and it's attacked now, redo move.
	{
		lastmove = mv;
		RedoMove();
		return -1;
	}

	//Promote pawn.
	if (myCol == Color::WHITE)
	{
		for (int i=1; i<9; i++) 
		{
			if (board[1][i]!=NULL && board[1][i]->tp ==PieceType::TP_PAWN) board[1][i]->tp = PieceType::TP_QUEEN;
		}
	}
	else
	{
		for (int i=1; i<9; i++) 
		{
			if (board[8][i]!=NULL && board[8][i]->tp ==PieceType::TP_PAWN) board[8][i]->tp = PieceType::TP_QUEEN;
		}
	}
	for (int i=1; i<9; i++)
	{
		for (int j=1; j<9; j++)
		{
			// Find opponent king and check if it is checkmated.
			if (board[i][j] != NULL && board[i][j]->tp == PieceType::TP_KING && board[i][j]->col != myCol)
			{
				if (isCheckMated(i, j)) return 999;
				else return 0;
			}
		}
	}
	return 0;
}

void Game::SaveGame() //Save game (Not completely)
{
	std::ofstream ofs("game.sav");
	ofs.write(InitFEN,strlen(InitFEN));
}

void Game::StartGame() // Start Game.
{
	Init();
}

void Game::SetPiece(int i, int j, char c) // Set piece to board from FEN letter.
{
	switch(c)
	{
	case 'r':
		Game::board[i][j] = new Rook(Color::BLACK);
		break;
	case 'n':
		board[i][j] = new Knight(Color::BLACK);
		break;
	case 'b':
		board[i][j] = new Bishop(Color::BLACK);
		break;
	case 'q':
		board[i][j] = new Queen(Color::BLACK);
		break;
	case 'k':
		board[i][j] = new King(Color::BLACK);
		break;
	case 'p':
		board[i][j] = new Pawn(Color::BLACK);
		break;
	case 'R':
		board[i][j] = new Rook(Color::WHITE);
		break;
	case 'N':
		board[i][j] = new Knight(Color::WHITE);
		break;
	case 'B':
		board[i][j] = new Bishop(Color::WHITE);
		break;
	case 'Q':
		board[i][j] = new Queen(Color::WHITE);
		break;
	case 'K':
		board[i][j] = new King(Color::WHITE);
		break;
	case 'P':
		board[i][j] = new Pawn(Color::WHITE);
		break;
	default:
		throw -1;
	}
}

bool Game::isAttacked(int x, int y, Color col) //if is field [x,y] attacked by another color than "col"
{
	Color c = Color::BLACK;

	if (col == Color::BLACK)
	{
		c = Color::WHITE;
	}

	for (int i = 1; i < 9; i++)
	{
		for (int j = 1; j < 9; j++)
		{
			if (board[i][j] == NULL) continue;
			if (board[i][j]->col == c)
			{
				if (isValidMove(x, y, i,j, board[i][j]->tp)) 
					return true;
			}
		}
	}
	return false;
}

bool Game::isValidMove(int x, int y, int i, int j, PieceType tp) //Is [x,y] attacked by [i,j] ? 
{
	if (x == i && y == j) return false;

	int ii;

	switch(tp)
	{
	case PieceType::TP_KING:
		if (abs(x - i)<=1 && abs(y-j) <= 1 && (abs(x-i)!= 0 || abs(y-j)!= 0)) return true;
		if (x-i == 2 && ((King*)board[i][j])->moved == false && board[8][j]!=NULL && ((Rook *)board[8][j])->moved==false)
		{
			bool att = false;
			for (int ii=i; ii<=8; ii++)
			{
				if (isAttacked(ii,j,myCol)) att = true;
			}
			if (!att)
			{
				((Rook*)board[8][j])->moved = true;
				((King*)board[i][j])->moved = true;
				board[i+1][j] = board[8][j];
				board[8][j] = NULL;
				return true;
			}
		}
		
		if (i-x == 2 && ((King*)board[i][j])->moved == false && board[1][j] != NULL && ((Rook *)board[1][j])->moved==false)
		{
			bool att = false;
			for (int ii=i; ii<=1; ii--)
			{
				if (isAttacked(ii,j, myCol)) att = true;
			}
			if (!att)
			{
				((Rook*)board[1][j])->moved = true;
				((King*)board[i][j])->moved = true;
				board[i+1][j] = board[8][j];
				board[1][j] = NULL;
				return true;
			}
		}
		return false;

	case PieceType::TP_BISHOP:
		if (abs(x-i)==abs(y-j))
		{
			int c = abs(x-i);
			int dx = abs(x-i)/(x-i);
			int dy = abs(y-j)/(y-j);
			for (ii = 1; ii < c; ii++)
			{
				i+=dx;
				j+=dy;
				if (board[i][j] != NULL) return false;
			}
			return true;
		}
		return false;

	case PieceType::TP_KNIGHT:
		if (abs(x-i) + abs(y-j) == 3 && (abs(x-i) == 2 || abs(x-i) == 1))
			return true;
		return false;

	case PieceType::TP_PAWN:
		ii = 1;
		if (board[i][j]->col == Color::WHITE) ii = -1;

		if (x - i == ii)
		{
			if (abs(j-y)==1 && board[x][y]!=NULL && board[x][y] != board[i][j])
				return true;

			if (j == y && board[x][y] == NULL)
				return true;
		}

		if (x - i == 2 * ii && ((Pawn *)board[i][j])->mv2sq && board[i+ii][y] == NULL)
		{
			((Pawn*)board[i][j])->mv2sq = false;
			return true;
		}

		return false;
	case PieceType::TP_QUEEN:
		if (i == x)
		{
			if (j < y)
			{
				for (ii = j + 1; ii < y; ii++)
				{
					if (board[i][ii] != NULL) return false;
				}
			}
			else
			{
				for (ii = y + 1; ii < j; ii++)
				{
					if (board[i][ii] != NULL) return false;
				} 
			}
			return true;
		}

		if (j == y)
		{
			if (i < x)
			{
				for (ii = i + 1; ii < x; ii++)
				{
					if (board[ii][j] != NULL) return false;
				}
			}
			else
			{
				for (ii = x + 1; ii < i; ii++)
				{
					if (board[ii][j] != NULL) return false;
				} 
			}
			return true;
		}

		if (abs(x-i)==abs(y-j))
		{
			int c = abs(x-i);
			int dx = abs(x-i)/(x-i);
			int dy = abs(y-j)/(y-j);
			for (ii = 1; ii < c; ii++)
			{
				i+=dx;
				j+=dy;
				if (board[i][j] != NULL) return false;
			}
			return true;
		}
		return false;
		
	case PieceType::TP_ROOK:
		if (x == i)
		{
			if (j < y)
			{
				for (ii = j + 1; ii < y; ii++)
				{
					if (board[i][ii] != NULL) return false;
				}
			}
			else
			{
				for (ii = y + 1; ii < j; ii++)
				{
					if (board[i][ii] != NULL) return false;
				} 
			}
			return true;
		}
		else
		{
			if (y == j)
			{
				if (i < x)
				{
					for (ii = i + 1; ii < x; ii++)
					{
						if (board[ii][j] != NULL) return false;
					}
				}
				else
				{
					for (ii = x + 1; ii < i; ii++)
					{
						if (board[ii][j] != NULL) return false;
					} 
				}
				return true;
			}
		}
		return false;
	}
}

void Game::RedoMove() // Redo last move
{
	int fromx = lastmove[0] - 'a' + 1;
	int fromy = lastmove[1] - '0';
	int tox = lastmove[2] - 'a' + 1;
	int toy = lastmove[3] - '0';
	board[fromx][fromy] = board[tox][toy];

		board[tox][toy] = last;
		last = NULL;
}

bool Game::isCheckMated(int kingposx, int kingposy) // If opponent king is checkemated.  
{
	Piece * p1 = board[kingposx][kingposy];
	Color c = Color::WHITE;
	
	if (myCol == Color::WHITE) c = Color::BLACK;

	if (!isAttacked(kingposx, kingposy, c)) 
	{
		return false;
	}


	//If king can escaped: 
	for (int i=-1; i<= 1; i++)
	{
		for (int j=-1; j<= 1; j++)
		{
			if (i != 0 || j!=0)
			{
				if ((kingposx+i < 1 || kingposx+i > 8 || kingposy + j < 1 || kingposy +j > 8) || (board[kingposx+i][kingposy]!=NULL && board[kingposx+i][kingposy]->col!=myCol)) continue;
				
				bool b = true;
				for (int ii=1; ii<9; ii++)
				{
					for (int jj=1; jj<9; jj++)
					{
						if (board[ii][jj] != NULL && board[ii][jj]->col == myCol)
						{
							if (isValidMove(kingposx+i, kingposy + j, ii, jj, board[ii][jj]->tp)) b = false;
						}
						//board[kingposx+i][kingposy+j] == NULL || board[kingposx+i][kingposy+j]->col != board[kingposx][kingposy]->col) && !isAttacked(kingposx+i, kingposy+j))
					}
				}
				if (b) return false;
			}
		}
	}



	bool capture = false;
	bool cover = false;

	// if my pieces, which check opponent, can be captured or covered by his other pieces.
	for (int ii=1; ii<9; ii++)
	{
		for (int jj=1; jj<9; jj++)
		{
			if (board[ii][jj] != NULL && board[ii][jj]->col == myCol)
			{
				if (isValidMove(ii,jj,kingposx, kingposy, board[ii][jj]->tp)) 
				{
					if (isAttacked(ii,jj, myCol)) capture = true;

					if (board[ii][jj] != NULL && board[ii][jj]->tp == PieceType::TP_KNIGHT) cover = false;
					else
					{
						for (int i=1; i<9; i++)
						{
							for (int j=1; j<9; j++)
							{
								if (board[i][j] != NULL && board[i][j]->col != myCol)
								{
									int dx = abs(ii - kingposx)/(ii-kingposx);
									int dy = abs(jj - kingposy)/(jj-kingposy);

									if (abs(ii-kingposx) > 0)
									{
										int x = kingposx;
										int y = kingposy;

										for (int xx = 1; xx < abs(ii-kingposx); xx++)
										{
											x += dx;
											y += dy;

											if (board[i][j]->tp == PieceType::TP_KING) continue;

											if (isValidMove(x,y,i,j,board[i][j]->tp))
											{
												cover = true;
											}
										}
									}
									else
									{
										int x = kingposx;
										int y = kingposy;

										for (int xx = 1; xx < abs(jj-kingposy); xx++)
										{
											x += dx;
											y += dy;
											if (board[i][j]->tp == PieceType::TP_KING) continue;
											if (isValidMove(x,y,i,j,board[i][j]->tp)) 
												cover = true;
										}
									}
								}
							}
						}
					}
				}
			}
			//board[kingposx+i][kingposy+j] == NULL || board[kingposx+i][kingposy+j]->col != board[kingposx][kingposy]->col) && !isAttacked(kingposx+i, kingposy+j))
		}
	}

	if (capture || cover) return false;

	return true;
}


